/**************************************************************
*  Apple LLVM version 10.0.0 (clang-1000.10.43.1)             *
*  Copyright (C) 2021 Xuan-Yu-San 307100890@qq.com.           *
*                                                             *
*  This file is part of little-nginx.                         *
*  Little-NGINX is a castration version NGINX for learning    *
*  HTTP Message.                                              *
*                                                             *
*  @file     Server.h                                         *
*  @github   https://gitee.com/xuanyusan/little_nginx.git     *
*  @license  MIT License (MIT)                                *
**************************************************************/

#ifndef NGINXCONFIG_HPP
#define NGINXCONFIG_HPP

#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include <vector>
#include <queue>
#include <algorithm>

#include "util.hpp"

using namespace std;

class NginxConfig {
private:
    string location;
    string root;
    vector<string> index_files;
    string proxy_pass;
    pair<string, string> proxy_redirect;
    pair<string, string> rewrite;
public:
    string getLocation() { return this->location; };
    string getProxyHost() { return DNS_resolver(this->proxy_host); };
    int getProxyPort() { return this->proxy_port; };
    pair<string, string> getProxyRedirect() { return this->proxy_redirect; };
    friend bool operator < (NginxConfig, NginxConfig);
    friend ostream& operator << (ostream&, NginxConfig);
    NginxConfig(string, string, vector<string>, string, pair<string, string>, pair<string, string>);
    bool check_proxy_redirect();
    bool check_rewrite();
    string get_rewrite_url(string);
    bool check_root();
    string getStaticFile(string);
    string proxy_protocol;
    string proxy_host;
    int proxy_port;
    string proxy_server;
    string proxy_path;
    ~NginxConfig();
};

bool operator <(NginxConfig A, NginxConfig B) {
    return A.location.size() == B.location.size() ? A.location < B.location : A.location.size() < B.location.size();
}

ostream& operator <<(ostream& out, vector<string> A) {
    for(int i=0; i<A.size(); i++) {
        out << A[i] << ' ';
    }
    return out;  
}

ostream& operator <<(ostream& out, NginxConfig A) {
    out << "\033[36;5m# NGINX Config\033[0m" << endl;
    return out << "location " << A.location << " {" << endl
    << (A.root.empty()?"":"\troot ") << A.root << (A.root.empty()?"":";\n")
    << (A.index_files.empty()?"":"\t") << A.index_files << (A.index_files.empty()?"":";\n")
    << (A.proxy_pass.empty()?"":"\tproxy_pass ") << A.proxy_pass << (A.proxy_pass.empty()?"":";\n")
    << (A.check_proxy_redirect()?"\tproxy_redirect ":"") << A.proxy_redirect.first << (A.check_proxy_redirect()?" ":"") << A.proxy_redirect.second << (A.check_proxy_redirect()?";\n":"")
    << (A.check_rewrite()?"\trewrite ":"") << A.rewrite.first << (A.check_rewrite()?" ":"") << A.rewrite.second << (A.check_rewrite()?";\n":"")
    << "}" << endl;
}

NginxConfig::NginxConfig(string location, string root, vector<string> index_files, string proxy_pass, pair<string, string> proxy_redirect, pair<string, string> rewrite):location(location), root(root), index_files(index_files), proxy_pass(proxy_pass), proxy_redirect(proxy_redirect), rewrite(rewrite) {
    string res_part;
    int index = proxy_pass.find("://");
    if(index>=0){
        this->proxy_protocol = proxy_pass.substr(0, index);
        res_part = proxy_pass.substr(index+3);
        index = res_part.find("/");
        if(index>=0){
            this->proxy_server = res_part.substr(0, index);
            this->proxy_path = res_part.substr(index);
            res_part = this->proxy_server;
            index = res_part.find(":");
            if(index<0) {
                this->proxy_port = this->proxy_protocol=="http"?80:this->proxy_protocol=="https"?443:-1;
                this->proxy_host = res_part;
            } else {
                this->proxy_port = atoi(res_part.substr(index+1).c_str());
                this->proxy_host = res_part.substr(0, index);
            }
        } else {
            this->proxy_server = res_part;
            res_part = res_part;
            index = res_part.find(":");
            if(index<0) {
                this->proxy_port = this->proxy_protocol=="http"?80:this->proxy_protocol=="https"?443:-1;
                this->proxy_host = res_part;
            } else {
                this->proxy_port = atoi(res_part.substr(index+1).c_str());
                this->proxy_host = res_part.substr(0, index);
            }
        }
    }
}

bool NginxConfig::check_proxy_redirect() {
    return !(this->proxy_redirect.first.empty()||this->proxy_redirect.second.empty());
}
bool NginxConfig::check_rewrite() {
    return !(this->rewrite.first.empty()||this->rewrite.second.empty());
}
string NginxConfig::get_rewrite_url(string url) {
    int index = url.find(this->rewrite.first);
    string location = url.replace(index, this->rewrite.first.size(), this->rewrite.second);
    return location;
};
bool NginxConfig::check_root() {
    return !this->root.empty();
};
string NginxConfig::getStaticFile(string path="") {
    if(path.empty()||path=="/"){
        for(int i=0;i<this->index_files.size();i++) {
            ifstream fp(this->root+this->index_files[i]);
            if(!fp) continue;
            fp.close();
            return this->root+this->index_files[i];
        }
    } else {
        ifstream fp(this->root+path.substr(1));
        if(fp) {
            return this->root+path.substr(1);
        }
    }
    return "";
}

NginxConfig::~NginxConfig() {}

#endif